第一章 day01 搭建环境 CMS服务端开发

1 项目初始化—见源代码 工程

image-20190420104707268

2 页面查询接口定义-定义接口

1.1 Response返回值的 类源代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@ToString
public enum CommonCode implements ResultCode{

SUCCESS(true,10000,"操作成功!"),
FAIL(false,11111,"操作失败!"),
UNAUTHENTICATED(false,10001,"此操作需要登陆系统!"),
UNAUTHORISE(false,10002,"权限不足,无权操作!"),
SERVER_ERROR(false,99999,"抱歉,系统繁忙,请稍后重试!");
// private static ImmutableMap<Integer, CommonCode> codes ;
//操作是否成功
boolean success;
//操作代码
int code;
//提示信息
String message;
private CommonCode(boolean success,int code, String message){
this.success = success;
this.code = code;
this.message = message;
}

@Override
public boolean success() {
return success;
}
@Override
public int code() {
return code;
}

@Override
public String message() {
return message;
}
}

1
2
3
4
5
6
7
8
9
public interface ResultCode {
//操作是否成功,true为成功,false操作失败
boolean success();
//操作代码
int code();
//提示信息
String message();

}

1
2
3
4
public interface Response {
public static final boolean SUCCESS = true;
public static final int SUCCESS_CODE = 10000;
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
@Data
@ToString
@NoArgsConstructor
public class ResponseResult implements Response {

//操作是否成功
boolean success = SUCCESS;

//操作代码
int code = SUCCESS_CODE;

//提示信息
String message;

public ResponseResult(ResultCode resultCode){
this.success = resultCode.success();
this.code = resultCode.code();
this.message = resultCode.message();
}

public static ResponseResult SUCCESS(){
return new ResponseResult(CommonCode.SUCCESS);
}
public static ResponseResult FAIL(){
return new ResponseResult(CommonCode.FAIL);
}

}

1
2
3
4
5
6
7
8
9
10
11
12
@Data
@ToString
public class QueryResponseResult extends ResponseResult {

QueryResult queryResult;

public QueryResponseResult(ResultCode resultCode,QueryResult queryResult){
super(resultCode);
this.queryResult = queryResult;
}

}

1
2
3
4
public interface CmsPageControllerApi {
// 页面查询
public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest);
}

image-20190420105400443


1.2 类的分析与讲解 TODO

// @@@@枚举和公共类的开发详细解答

// @@@@枚举和公共类的开发详细解答

/// @@@@枚举和公共类的开发详细解答

// @@@@枚举和公共类的开发详细解答

// @@@@枚举和公共类的开发详细解答


2 页面查询服务端开发-创建CMS服务工程-测试

image-20190420110355676

image-20190420110315914


image-20190420110530100


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<dependencies>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xc-service-api</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xc-framework-model</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xc-framework-utils</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.xuecheng</groupId>
<artifactId>xc-framework-common</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-freemarker</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-mongodb</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
<?xml version="1.0" encoding="UTF-8"?>

<configuration>
<!--定义日志文件的存储地址,使用绝对路径-->
<property name="LOG_HOME" value="d:/logs"/>

<!-- Console 输出设置 -->
<appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
<charset>utf8</charset>
</encoder>
</appender>

<!-- 按照每天生成日志文件 -->
<appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--日志文件输出的文件名-->
<fileNamePattern>${LOG_HOME}/xc.%d{yyyy-MM-dd}.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
</encoder>
</appender>

<!-- 异步输出 -->
<appender name="ASYNC" class="ch.qos.logback.classic.AsyncAppender">
<!-- 不丢失日志.默认的,如果队列的80%已满,则会丢弃TRACT、DEBUG、INFO级别的日志 -->
<discardingThreshold>0</discardingThreshold>
<!-- 更改默认的队列的深度,该值会影响性能.默认值为256 -->
<queueSize>512</queueSize>
<!-- 添加附加的appender,最多只能添加一个 -->
<appender-ref ref="FILE"/>
</appender>


<logger name="org.apache.ibatis.cache.decorators.LoggingCache" level="DEBUG" additivity="false">
<appender-ref ref="CONSOLE"/>
</logger>
<logger name="org.springframework.boot" level="DEBUG"/>
<root level="info">
<!--<appender-ref ref="ASYNC"/>-->
<appender-ref ref="FILE"/>
<appender-ref ref="CONSOLE"/>
</root>
</configuration>

  • 启动类编写代码
1
2
3
4
5
6
7
8
9
10
@SpringBootApplication(exclude = DataSourceAutoConfiguration.class)//连接mongodb必须排除datasourceautoconfiguration,class
@EntityScan("com.xuecheng.framework.domain.cms")//扫描实体类
@ComponentScan(basePackages = {"com.xuecheng.api"})//扫描接口
@ComponentScan(basePackages = {"com.xuecheng.manage_cms"})//扫描本项目下的所有类
@EnableMongoRepositories(basePackages = "com.xuecheng.manage_cms.dao")
public class ManageCmsApplication {
public static void main(String[] args) {
SpringApplication.run(ManageCmsApplication.class, args);
}
}

3 页面查询服务端开发-创建CMS服务工程- SSM

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

@RestController
@RequestMapping("/cms/page")
public class CmsPageController implements CmsPageControllerApi {


@Autowired
PageService pageService;

@Override
@GetMapping("/list/{page}/{size}")
public QueryResponseResult findList(@PathVariable("page") int page, @PathVariable("size") int size, QueryPageRequest queryPageRequest) {

return pageService.findList(page, size, queryPageRequest);
}
/**
*public class QueryPageRequest {
* //接受页面查询的条件
* //站点ID
* private String siteId;
* //页面ID
* private String pageId;
* //页面名称
* private String pageName;
* //别名
* private String pageAliase;
* //模版ID
* private String templateId;
* }
*/

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56

@Service
public class PageService {
@Autowired
CmsPageRepository cmsPageRepository;

public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest) {
//1。 分页参数
if (page <= 0) {
page = 1;
}
page = page - 1;

if (size <= 0) {
size = 10;
}

Pageable pageable = PageRequest.of(page, size);
Page<CmsPage> all = cmsPageRepository.findAll(pageable);

System.err.println("all=====" + all);
System.err.println("all.getContent()" + all.getContent());
System.err.println("all.getTotalElements()" + all.getTotalElements());
QueryResult queryResult = new QueryResult();
queryResult.setList(all.getContent());//数据列表
queryResult.setTotal(all.getTotalElements());//数据总记录数
System.err.println("queryResult" + queryResult);
QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS, queryResult);
return queryResponseResult;
}


/**
* public class QueryResult<T> {
* //数据列表
* private List<T> list;
* //数据总数
* private long total;
* }
*/

/**
*public class QueryPageRequest {
* //接受页面查询的条件
* //站点ID
* private String siteId;
* //页面ID
* private String pageId;
* //页面名称
* private String pageName;
* //别名
* private String pageAliase;
* //模版ID
* private String templateId;
*/
}
1
2
3
4
5
6
7
8
9
10
server:
port: 8080
spring:
application:
name: xc-service-manage-cms
data:
mongodb:
host: localhost
port: 27017
database: xccms
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24

@Configuration
@EnableSwagger2
public class Swagger2Configuration {
@Bean
public Docket createRestApi() {
return new Docket(DocumentationType.SWAGGER_2)
.apiInfo(apiInfo())
.select()
.apis(RequestHandlerSelectors.basePackage("com.xuecheng"))
.paths(PathSelectors.any())
.build();
}

private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("学成网api文档")
.description("学成网api文档")
// .termsOfServiceUrl("/")
.version("1.0")
.build();
}

}

1
2
3
4
5
//Api 只写接口
public interface CmsPageControllerApi {
// 页面查询
public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest);
}

第二章 day02 CMS前端开发

1 vue.js基础-MVVM模式 .

image-20190426091539128


第三章 day03-自定义查询页面-服务端-Dao

1 自定义查询 SpringDataMongoDB

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
  @Test
public void testFindByExample() {
//分页查询
int page = 0;
int size = 10;
Pageable pageable = PageRequest.of(page, size);
//条件值对象

CmsPage cmsPage = new CmsPage();


cmsPage.setPageAliase("轮播");
// //条件匹配器
// ExampleMatcher exampleMatcher = ExampleMatcher.matching();
// exampleMatcher = exampleMatcher.withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains());

ExampleMatcher exampleMatcher = ExampleMatcher.matching()
.withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains());

//定义Example
Example<CmsPage> example = Example.of(cmsPage, exampleMatcher);
Page<CmsPage> all = cmsPageRepository.findAll(example, pageable);
List<CmsPage> content = all.getContent();
System.out.println(content);
}
}

2 自定义查询页面。 服务端Dao开发

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public class PageService {
@Autowired
CmsPageRepository cmsPageRepository;

public QueryResponseResult findList(int page, int size, QueryPageRequest queryPageRequest) {
if (queryPageRequest == null) {
queryPageRequest = new QueryPageRequest();
}
//自定义条件查询
ExampleMatcher exampleMatcher =
ExampleMatcher.matching().withMatcher("pageAliase", ExampleMatcher.GenericPropertyMatchers.contains());

CmsPage cmsPage = new CmsPage();
if (StringUtils.isEmpty(queryPageRequest.getSiteId())) {
cmsPage.setSiteId(queryPageRequest.getSiteId());
}
if (StringUtils.isEmpty(queryPageRequest.getTemplateId())) {
cmsPage.setSiteId(queryPageRequest.getTemplateId());
}
if (StringUtils.isEmpty(queryPageRequest.getPageAliase())) {
cmsPage.setPageAliase(queryPageRequest.getPageAliase());
}
//定义条件对象
Example<CmsPage> example = Example.of(cmsPage, exampleMatcher);
//定义条件匹配器
//1。 分页参数
if (page <= 0) {
page = 1;
}
page = page - 1;

if (size <= 0) {
size = 10;
}
Pageable pageable = PageRequest.of(page, size);
Page<CmsPage> all = cmsPageRepository.findAll(example, pageable);//实现自定义查询 并且分页查询
QueryResult queryResult = new QueryResult();
queryResult.setList(all.getContent());//数据列表
queryResult.setTotal(all.getTotalElements());//数据总记录数
System.err.println("queryResult" + queryResult);
QueryResponseResult queryResponseResult = new QueryResponseResult(CommonCode.SUCCESS, queryResult);
return queryResponseResult;
}

image-20190517084147457

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 查询失物招领信息
* @return
*/
@GetMapping("/lost/list")
public ApiReturnObject findAllLostProperty (String materialName,Timestamp registerTime,String status) {
LostProperty obj=new LostProperty();
obj.setMaterialName(materialName);
obj.setRegisterTime(registerTime);
obj.setStatus(status);
//创建匹配器,即如何使用查询条件
ExampleMatcher matcher = ExampleMatcher.matching() //构建对象
.withMatcher("materialName", GenericPropertyMatchers.contains()) //姓名采用“开始匹配”的方式查询
.withMatcher("registerTime", GenericPropertyMatchers.contains()) //姓名采用“开始匹配”的方式查询
.withMatcher("status", GenericPropertyMatchers.contains()) //姓名采用“开始匹配”的方式查询
.withIgnorePaths("id"); //忽略属性:是否关注。因为是基本类型,需要忽略掉

//创建实例
Example<LostProperty> ex = Example.of(obj, matcher);
//查询
List<LostProperty> ls = lostPropertyRespository.findAll(ex);

return ApiReturnUtil.success(ls);
}

image-20190517084423440


自定义查询页面 前端

1
2
3
4
5
6
7
8
9
10
11
12
13
<el-form :model="params">
<el-select v-model="params.siteId" placeholder="请选择站点">
<el-option
v-for="item in siteList"
:key="item.siteId"
:label="item.siteName"
:value="item.siteId">
</el-option>
</el-select>
页面别名:
<el-input v-model="params.pageAliase" style="width: 100px"></el-input>
<el-button type="primary" size="small" v-on:click="query">查询</el-button>
</el-form>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<script>
import * as cmsApi from '../api/cms'
// <!--编写页面静态部分 即model vm部分-->
export default {
data() {
return {
siteList: [],
total: 1000,
params: {
page: 1,
size: 11,
siteId: '',
pageAliase: ''

},
list: []
}
},
methods: {
query: function () {
//调用服务端的接口 cms.js 调用
cmsApi.page_list(this.params.page, this.params.size, this.params).then((res) => {
this.list = res.queryResult.list;
this.total = res.queryResult.total;
})
},
changePage: function (page) {
alert(page);
this.params.page = page;
this.query();
}

},
//钩子函数
mounted() {
this.query();
this.siteList = [
{
siteId: '5a751fab6abb5044e0d19ea1',
siteName: '门户主站'
},
{
siteId: '102',
siteName: '测试站'
}
]
}
}
</script>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import http from './../../../base/api/public'
// import queryString from 'querystring'
const querystring = require('querystring');
let sysConfig = require('@/../config/sysConfig')


let apiUrl = sysConfig.xcApiUrlPre;
//定义方法请求 服务端的页面查询接口
export const page_list = (page, size, params) => {
//将params对象数据 JSON数据拼装成key value串 (queryString)
//请求 服务端的页面查询接口
//写这句话会出现BUG呀 页面出现不了信息 改变一下啊(S 大小写的问题 ==》queryString++stringify 注意S的大小写问题 )
let queryString = querystring.stringify(params);
return http.requestQuickGet(apiUrl + '/cms/page/list/' + page + '/' + size + "?" + queryString);
// var sysConfig = {
// xcApiUrlPre: '/api',
// return http.requestGet("apiUrl+'/cms/page/list/'+page+'/'+size);
};

image-20190517142747998


1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("/cms/page")
public class CmsPageController implements CmsPageControllerApi {


@Autowired
PageService pageService;

@Override
@GetMapping("/list/{page}/{size}")
public QueryResponseResult findList(@PathVariable("page") int page, @PathVariable("size") int size, QueryPageRequest queryPageRequest) {

return pageService.findList(page, size, queryPageRequest);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@Data
public class QueryPageRequest {
//接受页面查询的条件
//站点ID
private String siteId;
//页面ID
private String pageId;
//页面名称
private String pageName;
//别名
private String pageAliase;
//模版ID
private String templateId;
}

3 新增页面

1
2
@ApiOperation("新增页面")
public CmsPageResult add(CmsPage cmsPage);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public CmsPageResult add(CmsPage cmsPage) {
//校验页面名称 站点ID 页面webpath的唯一性
//根据页面名称 站点ID 页面webpath去Cms——page
//集合 如果查到说明此页面已经存在 如果查询不到继续添加页面
//调用dao新增页面

CmsPage cmsPagefindBy = cmsPageRepository.findByPageNameAndSiteIdAndPageWebPath
(cmsPage.getPageName(), cmsPage.getSiteId(), cmsPage.getPageWebPath());

if (cmsPagefindBy == null) {
cmsPage.setPageId(null);
cmsPageRepository.save(cmsPage);
return new CmsPageResult(CommonCode.SUCCESS, cmsPage);
}
return new CmsPageResult(CommonCode.FAIL, null);
/**
* public CmsPageResult(ResultCode resultCode, CmsPage cmsPage) {
* super(resultCode);
* this.cmsPage = cmsPage;
* }
*/
}

1
CmsPage findByPageNameAndSiteIdAndPageWebPath(String pageName, String siteId, String pageWebPath);
1
2
3
4
5
6
7
8
9
@Data
public class CmsPageResult extends ResponseResult {
CmsPage cmsPage;

public CmsPageResult(ResultCode resultCode, CmsPage cmsPage) {
super(resultCode);
this.cmsPage = cmsPage;
}
}

4 新增页面 前端

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
<template>
<div>
<el-form :model="pageForm" label-width="80px" :rules="pageFormRules" ref="pageForm">
<el-form-item label="所属站点" prop="siteId">
<el-select v-model="pageForm.siteId" placeholder="请选择站点">
<el-option
v-for="item in siteList"
:key="item.siteId"
:label="item.siteName"
:value="item.siteId">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="选择模版" prop="templateId">
<el-select v-model="pageForm.templateId" placeholder="请选择">
<el-option
v-for="item in templateList"
:key="item.templateId"
:label="item.templateName"
:value="item.templateId">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="页面名称" prop="pageName">
<el-input v-model="pageForm.pageName" auto-complete="off"></el-input>
</el-form-item>

<el-form-item label="别名" prop="pageAliase">
<el-input v-model="pageForm.pageAliase" auto-complete="off"></el-input>
</el-form-item>
<el-form-item label="访问路径" prop="pageWebPath">
<el-input v-model="pageForm.pageWebPath" auto-complete="off"></el-input>
</el-form-item>

<el-form-item label="物理路径" prop="pagePhysicalPath">
<el-input v-model="pageForm.pagePhysicalPath" auto-complete="off"></el-input>
</el-form-item>

<el-form-item label="类型">
<el-radio-group v-model="pageForm.pageType">
<el-radio class="radio" label="0">静态</el-radio>
<el-radio class="radio" label="1">动态</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker type="datetime" placeholder="创建时间" v-model="pageForm.pageCreateTime"></el-date-picker>
</el-form-item>

</el-form>
<div slot="footer" class="dialog-footer">
<el-button type="primary" @click="addSubmit">提交</el-button>
<el-button type="primary" @click="go_back">返回</el-button>
</div>
</div>

</template>
<script>
import * as cmsApi from '../api/cms'
// <!--编写页面静态部分 即model vm部分-->
export default {
data() {
return {
siteList: [],
templateList: [],
pageForm: {
siteId: '',
templateId: '',
pageName: '',
pageAliase: '',
pageWebPath: '',
pageParameter: '',
pagePhysicalPath: '',
pageType: '',
pageCreateTime: new Date()
}
}
},
//钩子函数
mounted() {
//初始化站点列表
this.siteList = [
{
siteId: '5a751fab6abb5044e0d19ea1',
siteName: '门户主站'
},
{
siteId: '102',
siteName: '测试站'
}
];
//模板列表
this.templateList = [
{
templateId: '5a962b52b00ffc514038faf7',
templateName: '首页'
},
{
templateId: '5a962bf8b00ffc514038fafa',
templateName: '轮播图'
}
]
},
methods: {
addSubmit: function () {
alert("hexo");
}
}
}

</script>

<!--编写页面样式 非必须-->
<style>
</style>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import Home from '@/module/home/page/home.vue';
import page_list from '@/module/cms/page/page_list.vue';
import page_add from '@/module/cms/page/page_add.vue';

export default [{
path: '/',
component: Home,
name: 'CMS',//菜单名称
hidden: false,
children: [
{
path: '/cms/page/list',//http://localhost:11000/#/cms/page/list
name: '页面列表',
component: page_list,
hidden: false
},
{
path: '/cms/page/add',//http://localhost:11000/#/cms/page/add
name: '新增页面',
component: page_add,
hidden: true
}
]
}/*,
{
path: '/login',
component: Login,
name: 'Login',
hidden: true
}*/
]

5 页面完善(query参数 返回 带参数)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
methods: {
addSubmit: function () {
alert("hexo");
},



go_back: function () {
this.$router.push({
path: '/cms/page/list',
query: {
page: this.$route.query.page,//取出路由中的参数
siteId: this.$route.query.siteId
}
});
}
1
2
3
4
5
6
7
8
<!--query :http://localhost:11000/#/cms/page/add?page=1&siteId=5a751fab6abb5044e0d19ea1
带参数-->
<router-link class="mui‐tab‐item" :to="{path:'/cms/page/add',
query:{
page:this.params.page,
siteId:this.params.siteId

}}">
1
2
3
4
5
6
7
 
//钩子函数
created() {
//进入页面取出参数 没有渲染 取出路由里面的参数 赋值给参数对象
this.params.page = Number.parseInt(this.$route.query.page) || 1;
this.params.siteId = this.$route.query.siteId;
},
  • 校验规则
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
export default {
data() {
return {
siteList: [],
templateList: [],
pageForm: {
siteId: '',
templateId: '',
pageName: '',
pageAliase: '',
pageWebPath: '',
pageParameter: '',
pagePhysicalPath: '',
pageType: '',
pageCreateTime: new Date()
},
pageFormRules: {
siteId:[
{required: true, message: '请选择站点', trigger: 'blur'}
],
templateId:[
{required: true, message: '请选择模版', trigger: 'blur'}
],
pageName: [
{required: true, message: '请输入页面名称', trigger: 'blur'}
],
pageWebPath: [
{required: true, message: '请输入访问路径', trigger: 'blur'}
],
pagePhysicalPath: [
{required: true, message: '请输入物理路径', trigger: 'blur'}
]
},

}
},
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
methods: {
addSubmit: function () {
this.$refs.pageForm.validate((valid) => {//表单校验
if (valid) {//表单校验通过
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.addLoading = true;
//修改提交请求服务端的接口
cmsApi.page_edit(this.pageId, this.pageForm).then((res) => {
console.log(res);
if (res.success) {
this.addLoading = false;
this.$message({
message: '提交成功',
type: 'success'
});
//返回
this.go_back();

} else {
this.addLoading = false;
this.$message.error('提交失败');
}
});
});
}
});
}

},

6.APi —新建页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
methods: {
addSubmit: function () {
this.$refs['pageForm'].validate((valid) => {
if (valid) {
//加一个确认提示
this.$confirm('您确认提交吗?', '提示', {}).then(() => {
cmsApi.page_add(this.pageForm).then(res => {
//解析响应内容
if (res.success) {
this.$message({
message: 'ok',
type: 'success'
})
//将表单清空
this.$refs['pageForm'].resetField();
} else {
this.$message.error("提交失败");
}
}
);
});


}
},);
},
//返回
go_back: function () {
this.$router.push({
path: '/cms/page/list',
query: {
page: this.$route.query.page,//取出路由中的参数
siteId: this.$route.query.siteId
}
})
}
},

1
2
3
4
export const page_add = params => {
//http://localhost:8080/cms/page/add
return http.requestPost(apiUrl + '/cms/page/add', params);
};

7 修改页面—-接口开发

1
2
3
4
5
6
7
8
//根据页面ID 查询页面信息
@ApiOperation("根据页面ID 查询页面信息")
public CmsPage findById(String id);


//修改页面
@ApiOperation("修改页面")
public CmsPageResult edit(String id, CmsPage cmsPage);
1
2
3
4
5
6
7
8
9
10
11
@Override
@GetMapping("/get/{id}")
public CmsPage findById(@PathVariable("id") String id) {
return pageService.getById(id);
}

@Override
@PutMapping("/edit/{id}")
public CmsPageResult edit(@PathVariable("id") String id, @RequestBody CmsPage cmsPage) {
return pageService.update(id, cmsPage);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 //修改页面

public CmsPageResult update(String id, CmsPage cmsPage) {
//根据ID从数据库查询页面信息

CmsPage cmsPagebyId = this.getById(id);
if (cmsPagebyId != null) {
cmsPagebyId.setPageAliase(cmsPage.getPageAliase());
cmsPagebyId.setPageName(cmsPage.getPageName());
cmsPagebyId.setPageId(cmsPage.getPageId());
cmsPagebyId.setTemplateId(cmsPage.getTemplateId());
cmsPagebyId.setPagePhysicalPath(cmsPage.getPagePhysicalPath());
cmsPagebyId.setSiteId(cmsPage.getSiteId());
cmsPageRepository.save(cmsPagebyId);
return new CmsPageResult(CommonCode.SUCCESS, cmsPagebyId);
}
return new CmsPageResult(CommonCode.FAIL, null);
}
}
1
2
3
4
5
6
7
8
9
10
    public CmsPage getById(String id) {
Optional<CmsPage> optional = cmsPageRepository.findById(id);
//optional.isPresent() ==>如果值存在则使用该值调用 consumer , 否则不做任何事情。
// 这是一个可以包含或者不包含非 null 值的容器。如果值存在则 isPresent()方法会返回 true,调用 get() 方法会返回该对象
if (optional.isPresent()) {
CmsPage cmsPage = optional.get();
return cmsPage;
}
return null;
}

8 修改页面。 前端

1
2
3
4
5
6
7
8
9
10
11
12
<el-table-column
label="操作"
width="80">
<template slot-scope="page">
<el-button
size="small"
type="text"
v-on:click="edit(page.row.pageId)">编辑
</el-button>
</template>
</el-table-column>
</el-table>
1
2
3
4
5
6
7
edit: function (pageId) {
//打开修改页面
this.$router.push({
//少了一个"/" 注意
path:'/cms/page/edit/' + pageId
})
}

1
2
3
4
5
6
7
8
9
10
11
import page_edit from '@/module/cms/page/page_edit.vue';




{
path: '/cms/page/edit/:pageId', //http://localhost:11000/#/cms/page/edit5a795ac7dd573c04508f3a56
name: '修改页面',
component: page_edit,
hidden: true
}

1
2
3
4
5
6
7
8
9
10
created: function () {
this.pageId=this.$route.params.pageId;
//根据主键查询页面信息
cmsApi.page_get(this.pageId).then((res) => {
console.log(res);
if(res){
this.pageForm = res;
}
});
},

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
<template>
<div>
<el-form :model="pageForm" label-width="80px" :rules="pageFormRules" ref="pageForm" >
<el-form-item label="所属站点" prop="siteId">
<el-select v-model="pageForm.siteId" placeholder="请选择站点">
<el-option
v-for="item in siteList"
:key="item.siteId"
:label="item.siteName"
:value="item.siteId">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="选择模版" prop="templateId">
<el-select v-model="pageForm.templateId" placeholder="请选择">
<el-option
v-for="item in templateList"
:key="item.templateId"
:label="item.templateName"
:value="item.templateId">
</el-option>
</el-select>
</el-form-item>
<el-form-item label="页面名称" prop="pageName">
<el-input v-model="pageForm.pageName" auto-complete="off" ></el-input>
</el-form-item>

<el-form-item label="别名" prop="pageAliase">
<el-input v-model="pageForm.pageAliase" auto-complete="off" ></el-input>
</el-form-item>
<el-form-item label="访问路径" prop="pageWebPath">
<el-input v-model="pageForm.pageWebPath" auto-complete="off" ></el-input>
</el-form-item>

<el-form-item label="物理路径" prop="pagePhysicalPath">
<el-input v-model="pageForm.pagePhysicalPath" auto-complete="off" ></el-input>
</el-form-item>
<el-form-item label="数据Url" prop="dataUrl">
<el-input v-model="pageForm.dataUrl" auto-complete="off" ></el-input>
</el-form-item>
<el-form-item label="类型">
<el-radio-group v-model="pageForm.pageType">
<el-radio class="radio" label="0">静态</el-radio>
<el-radio class="radio" label="1">动态</el-radio>
</el-radio-group>
</el-form-item>
<el-form-item label="创建时间">
<el-date-picker type="datetime" placeholder="创建时间" v-model="pageForm.pageCreateTime"></el-date-picker>
</el-form-item>

</el-form>
<div slot="footer" class="dialog-footer">
<el-button @click="go_back">返回</el-button>
<el-button type="primary" @click.native="editSubmit" :loading="addLoading">提交</el-button>
</div>
</div>
</template>
<script>
import * as cmsApi from '../api/cms'
export default{
data(){
return {
//页面id
pageId:'',
//模版列表
templateList:[],
addLoading: false,//加载效果标记
//新增界面数据
pageForm: {
siteId:'',
templateId:'',
pageName: '',
pageAliase: '',
pageWebPath: '',
dataUrl:'',
pageParameter:'',
pagePhysicalPath:'',
pageType:'',
pageCreateTime: new Date()
},
pageFormRules: {
siteId:[
{required: true, message: '请选择站点', trigger: 'blur'}
],
templateId:[
{required: true, message: '请选择模版', trigger: 'blur'}
],
pageName: [
{required: true, message: '请输入页面名称', trigger: 'blur'}
],
pageWebPath: [
{required: true, message: '请输入访问路径', trigger: 'blur'}
],
pagePhysicalPath: [
{required: true, message: '请输入物理路径', trigger: 'blur'}
]
},
siteList:[]
}
},
methods:{
go_back(){
this.$router.push({
path: '/cms/page/list', query: {
page: this.$route.query.page,
siteId:this.$route.query.siteId
}
})
},
editSubmit(){
this.$refs.pageForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.addLoading = true;
cmsApi.page_edit(this.pageId,this.pageForm).then((res) => {
console.log(res);
if(res.success){
this.addLoading = false;
this.$message({
message: '提交成功',
type: 'success'
});
//返回
this.go_back();

}else{
this.addLoading = false;
this.$message.error('提交失败');
}
});
});
}
});
}

},
created: function () {
this.pageId=this.$route.params.pageId;
//根据主键查询页面信息
cmsApi.page_get(this.pageId).then((res) => {
console.log(res);
if(res){
this.pageForm = res;
}
});
},
mounted:function(){

//初始化站点列表
this.siteList = [
{
siteId:'5a751fab6abb5044e0d19ea1',
siteName:'门户主站'
},
{
siteId:'102',
siteName:'测试站'
}
]
//模板列表
this.templateList = [
{
templateId:'5a962b52b00ffc514038faf7',
templateName:'首页'
},
{
templateId:'5a962bf8b00ffc514038fafa',
templateName:'轮播图'
}
]
}
}
</script>
<style>

</style>

1
2
3
export const page_get = id=> {
return http.requestQuickGet(apiUrl + '/cms/page/get/'+id)
};

9.修改页面 API 调用

1
2
3
export const page_edit = (id,params)=> {
return http.requestPut(apiUrl + '/cms/page/edit/'+id,params)
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
editSubmit(){
this.$refs.pageForm.validate((valid) => {
if (valid) {
this.$confirm('确认提交吗?', '提示', {}).then(() => {
this.addLoading = true;
cmsApi.page_edit(this.pageId,this.pageForm).then((res) => {
console.log(res);
if(res.success){
this.addLoading = false;
this.$message({
message: '提交成功',
type: 'success'
});
//返回
this.go_back();

}else{
this.addLoading = false;
this.$message.error('提交失败');
}
});
});
}
});
}

10.删除页面

1
2
@ApiOperation("删除页面")
public ResponseResult delete(String id);

1
2
3
4
5
@Override
@DeleteMapping("/del/{id}")
public ResponseResult delete(@PathVariable("id") String id) {
return pageService.delete(id);
}

1
2
3
4
5
6
7
8
9
10
//根据ID删除数据
public ResponseResult delete(String id) {
Optional<CmsPage> optional = cmsPageRepository.findById(id);
if (optional.isPresent()) {
cmsPageRepository.deleteById(id);
return new ResponseResult(CommonCode.SUCCESS);
}
return new ResponseResult(CommonCode.FAIL);

}

11.删除页面 前端开发

1
2
3
4
5
<el-button
size="small"
type="text"
v-on:click="del(page.row.pageId)">删除
</el-button>
1
2
3
4
5
6
7
8
9
10
11
12
del: function (pageId) {
this.$confirm('您确认提交吗', '提示', {}).then(() => {
//调用服务端的接口
cmsApi.page_del(pageId).then(res => {
if (res.success) {
this.$message.success("删除成功");
this.query()
} else this.$message.error("删除失败")
})
})
}
},

1
2
3
export const page_del = (id) => {
return http.requestDelete(apiUrl + '/cms/page/del/' + id)
};

第四章 页面静态化 Freemark

轮播图DataUrl接口开发

1
2
3
4
public interface CmsConfigControllerApi {
@ApiOperation("根据ID查询CMS 配置信息")
public CmsConfig getmodel(String id);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@RestController
@RequestMapping("cms/config")
public class CmsConfigController implements CmsConfigControllerApi {

@Autowired
PageService pageService;

@Override
@GetMapping("/getmodel/{id}")
public CmsConfig getmodel(@PathVariable("id") String id) {
return pageService.getConfigById(id);
}

}
1
2
3
public interface CmsConfigRepository extends MongoRepository<CmsConfig, String> {

}
1
2
3
4
5
6
7
8
9
10
11
    //根据ID 查询Cmsconfig
public CmsConfig getConfigById(String id) {
Optional<CmsConfig> optional = cmsConfigRepository.findById(id);
if (optional.isPresent()) {
CmsConfig cmsConfig = optional.get();
return cmsConfig;
}
return null;
}

}

image-20190523163423617


远程接口调用

a
1
2
3
4
@Bean
public RestTemplate restTemplate() {
return new RestTemplate(new OkHttp3ClientHttpRequestFactory());
}
1
2
3
4
5
6
7
8
9
10
11
12

@Autowired
RestTemplate restTemplate;

@Test
public void TestRestTemplate() {
ResponseEntity<Map> forEntity = restTemplate.getForEntity("http://localhost:8080/cms/config/getmodel/5a791725dd573c3574ee333f", Map.class);

Map body = forEntity.getBody();

System.out.println(body);
}

模版管理流程

image-20190523164028746

页面模版管理

1
2
3
4
5
6
<script type="text/javascript" 
src="http://www.xuecheng.com:8888/plugins/jquery/dist/jquery.js">
</script>
<script type="text/javascript"
src="http://www.xuecheng.com:8888/plugins/bootstrap/dist/js/bootstrap.js">
</script>

image-20190524164838893


域名+端口号

image-20190524164947760

image-20190524164958470


1
2
3
4
5
6
7
<div class="item" style="background-image: url(http://www.xuecheng.com:8888/img/widget-bannerA.jpg);"></div>
<div class="item" style="background-image: url(http://www.xuecheng.com:8888/img/widget-banner3.png);"></div>
<div class="item" style="background-image: url(http://www.xuecheng.com:8888/img/widget-bannerB.jpg);"></div>
<div class="item" style="background-image: url(http://www.xuecheng.com:8888/img/widget-bannerA.jpg);"></div>
<div class="item" style="background-image: url(http://www.xuecheng.com:8888/img/widget-banner3.png);"></div>
</div>
<div class="indicators"></div>

GridFs

存文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootTest
@RunWith(SpringRunner.class)
public class GridFsTest {

@Autowired
GridFsTemplate gridFsTemplate;

//存文件
@Test
public void testGrodFsTemplate() throws FileNotFoundException {
//存模版文件 /Users/apple/Desktop/index_banner.ftl
File file = new File("/Users/apple/Desktop/index_banner.ftl");
//定义File
FileInputStream fileInputStream = new FileInputStream(file);
ObjectId objectId = gridFsTemplate.store(fileInputStream, "index_banner.ftl");
System.out.println(objectId);
}
}

image-20190530155232226

image-20190530161617605

image-20190530161732831 Fs.chunks

image-20190530161847076


读文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.xuecheng.manage_cms.config;

import com.mongodb.MongoClient;
import com.mongodb.client.MongoDatabase;
import com.mongodb.client.gridfs.GridFSBucket;
import com.mongodb.client.gridfs.GridFSBuckets;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.validation.Valid;

@Configuration
public class MongoConfig {

@Value("${spring.data.mongodb.database}")
String db;

@Bean
public GridFSBucket getGridFSBucket(MongoClient mongoClient) {
MongoDatabase database = mongoClient.getDatabase(db);
GridFSBucket bucket = GridFSBuckets.create(database);
return bucket;
}

}
1
2
@Autowired
GridFSBucket gridFSBucket;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
//读文件
@Test
public void queryFile() throws IOException {
//根据文件ID 查询文件
GridFSFile gridFSFile = gridFsTemplate.findOne(Query.query(Criteria.where("_id").is("5cef9623b65d21c6dd00f9fc")));
//打开一个下载流对象

GridFSDownloadStream gridFSDownloadStream =
gridFSBucket.openDownloadStream(gridFSFile.getObjectId());

//创建GridFsResource对象 获取流

GridFsResource gridFsResource = new GridFsResource(gridFSFile, gridFSDownloadStream);
//从流中取数据
String content = IOUtils.toString(gridFsResource.getInputStream(), "UTF-8");
System.out.println(content);

}
}

屏幕快照 2019-05-30 下午4.08.52

模版管理

![image-20190530165023348](../../../Users/apple/Library/Application Support/typora-user-images/image-20190530165023348.png)


页面静态化

第五章. Rabbitmq

image-20190601082858353

生产者 Producter

1
2
3
4
5
6
7
8
9
10
<dependencies>
<dependency>
<groupId>com.rabbitmq</groupId>
<artifactId>amqp-client</artifactId>
<version>4.0.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
public class Producer01 {
//队列名称
private static final String QUEUE = "helloworld";

public static void main(String[] args) {
//通过连接工厂创建新的连接 和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq的服务可以设置多个虚拟机 每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");
Connection connection = null;
try {
//1 建立新连接
connection = connectionFactory.newConnection();
//创建会话通道 生产者和mq服务所有通信都在channel通道中完成
Channel channel = connection.createChannel();
//申明队列:如果队列在mq中没有 则要创建
//参数:
//String queue boolean durable boolean exclusive boolean autoDelete Map<String,Object> arguments
/**
* 参数明细
* 1。(queue)队列名称
* 2。(durable)是否持久化 mq重启后 队列还在
* 3。(exclusive)是否独占连接 队列只允许在该连接中访问 如果连接关闭队列自动删除
* 如果将此参数设置true可用于临时队列的创建
* 4。(autoDelete) 自动删除 队列不再使用时是否自动删除此队列 如果此参数和exclusive设置成true就会变成临时队列
* 5。arguments 参数 可以设置一个队列的扩展参数 比如:设置存活时间等等
*/
channel.queueDeclare(QUEUE, true, false, false, null);
//发送消息
//参数 String exchange String routingKey BasicProperties props, byte[]body
/**
* 参数明细:
* 1。exchange 交换机 如果不指定使用mq的默认交换机 (设置为"")
* 2。routingKey 路由Key 交换机根据路由Key将消息转发的指定的队列,
* 如果使用默认交换机 routingKey要设置成队列的名称
* 3。props 消息的属性
* 4。body 消息内容
*/
String message = "Hello world";
channel.basicPublish("", QUEUE, null, message.getBytes());
System.out.println("send to mq " + message);
} catch (Exception e) {
e.printStackTrace();
} finally {
}
}
}

消费者 Consumer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
public class Consumer {
private static final String QUEUE = "helloworld";

public static void main(String[] args) throws IOException, TimeoutException {
//通过连接工厂创建新的连接 和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq的服务可以设置多个虚拟机 每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");


//建立新连接

Connection connection = connectionFactory.newConnection();
//创建会话通道 生产者和mq服务所有通信都在channel通道中完成
Channel channel = connection.createChannel();


//监听队列
//申明队列:如果队列在mq中没有 则要创建
//参数:
//String queue boolean durable boolean exclusive boolean autoDelete Map<String,Object> arguments
/**
* 参数明细
* 1。(queue)队列名称
* 2。(durable)是否持久化 mq重启后 队列还在
* 3。(exclusive)是否独占连接 队列只允许在该连接中访问 如果连接关闭队列自动删除
* 如果将此参数设置true可用于临时队列的创建
* 4。(autoDelete) 自动删除 队列不再使用时是否自动删除此队列 如果此参数和exclusive设置成true就会变成临时队列
* 5。arguments 参数 可以设置一个队列的扩展参数 比如:设置存活时间等等
*/
channel.queueDeclare(QUEUE, true, false, false, null);


//实现消费方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {
@Override
//当接收到消息后此方法将被调用
//参数 String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body
/**
* 1。ConsumerTag 消费者标签 用来标识消费者的
* 在监听队列设置channel.basucConsume
* 2。envelope 信封通过envelope
* 3。properties 消息属性
* 4。body 消息内容
*
*/
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//消息ID mq在channel中用来标识消息的id 可用于确认消息以接受
long deliveryTag = envelope.getDeliveryTag();
String string = new String(body, "utf-8");
System.out.println("receive:" + string);
System.out.println("===============================");
System.out.println(exchange);
System.out.println(deliveryTag);
}
};
//监听队列
//参数 String queue boolean autoAck Consumer callback
/**
* 参数明细
* 1。queue 队列名称
* 2。autoACK 自动回复 当消费者接收到消息后告诉MQ消息已经接受
* 若果将此参数设置为true表示自动回复mq false 通过变成实现
* 3⭐️ callback 消费方法 当消费者接受到消息要执行的方法
*/
channel.basicConsume(QUEUE, true, defaultConsumer);
}
}

工作队列模式

image-20190601093647856

image-20190601093601036


发布订阅模式

image-20190601094230863


image-20190601094505657


生产者 prducter_publish

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
package com.xuecheng.test.rabbitmq;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* @author Administrator
* @version 1.0
* @create 2018-06-17 18:10
**/
public class Producer02_publish {
//队列名称
private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
private static final String EXCHANGE_FANOUT_INFORM = "exchange_fanout_inform";

public static void main(String[] args) {
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");

Connection connection = null;
Channel channel = null;
try {
//建立新连接
connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
channel = connection.createChannel();
//声明队列,如果队列在mq 中没有则要创建
//参数:String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
/**
* 参数明细
* 1、queue 队列名称
* 2、durable 是否持久化,如果持久化,mq重启后队列还在
* 3、exclusive 是否独占连接,队列只允许在该连接中访问,如果connection连接关闭队列则自动删除,如果将此参数设置true可用于临时队列的创建
* 4、autoDelete 自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
* 5、arguments 参数,可以设置一个队列的扩展参数,比如:可设置存活时间
*/
channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
//声明一个交换机
//参数:String exchange, String type
/**
* 参数明细:
* 1、交换机的名称
* 2、交换机的类型
* fanout:对应的rabbitmq的工作模式是 publish/subscribe
* direct:对应的Routing 工作模式
* topic:对应的Topics工作模式
* headers: 对应的headers工作模式
*/
channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
//进行交换机和队列绑定
//参数:String queue, String exchange, String routingKey
/**
* 参数明细:
* 1、queue 队列名称
* 2、exchange 交换机名称
* 3、routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
*/
channel.queueBind(QUEUE_INFORM_EMAIL, EXCHANGE_FANOUT_INFORM, "");
channel.queueBind(QUEUE_INFORM_SMS, EXCHANGE_FANOUT_INFORM, "");
//发送消息
//参数:String exchange, String routingKey, BasicProperties props, byte[] body
/**
* 参数明细:
* 1、exchange,交换机,如果不指定将使用mq的默认交换机(设置为"")
* 2、routingKey,路由key,交换机根据路由key来将消息转发到指定的队列,如果使用默认交换机,routingKey设置为队列的名称
* 3、props,消息的属性
* 4、body,消息内容
*/
for (int i = 0; i < 5; i++) {
//消息内容
String message = "send inform message to user";
channel.basicPublish(EXCHANGE_FANOUT_INFORM, "", null, message.getBytes());
System.out.println("send to mq " + message);
}

} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接
//先关闭通道
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}


}
}

消费者consumer

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package com.xuecheng.test.rabbitmq;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.ConnectionFactory;
import com.rabbitmq.client.DefaultConsumer;
import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* @description:
* @author: apple
* @date: 2019-06-01 11:09
*/
public class Consumer02_subscribe_email {
//队列名称
private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
private static final String EXCHANGE_FANOUT_INFORM = "exchange_fanout_inform";

public static void main(String[] args) throws IOException, TimeoutException, TimeoutException {
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");

//建立新连接
Connection connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
Channel channel = connection.createChannel();
/**
* 参数明细
* 1、queue 队列名称
* 2、durable 是否持久化,如果持久化,mq重启后队列还在
* 3、exclusive 是否独占连接,队列只允许在该连接中访问,如果connection连接关闭队列则自动删除,如果将此参数设置true可用于临时队列的创建
* 4、autoDelete 自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
* 5、arguments 参数,可以设置一个队列的扩展参数,比如:可设置存活时间
*/
channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
//声明一个交换机
//参数:String exchange, String type
/**
* 参数明细:
* 1、交换机的名称
* 2、交换机的类型
* fanout:对应的rabbitmq的工作模式是 publish/subscribe
* direct:对应的Routing 工作模式
* topic:对应的Topics工作模式
* headers: 对应的headers工作模式
*/
channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
//进行交换机和队列绑定
//参数:String queue, String exchange, String routingKey
/**
* 参数明细:
* 1、queue 队列名称
* 2、exchange 交换机名称
* 3、routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
*/
channel.queueBind(QUEUE_INFORM_EMAIL, EXCHANGE_FANOUT_INFORM, "");

//实现消费方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {

/**
* 当接收到消息后此方法将被调用
* @param consumerTag 消费者标签,用来标识消费者的,在监听队列时设置channel.basicConsume
* @param envelope 信封,通过envelope
* @param properties 消息属性
* @param body 消息内容
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//消息id,mq在channel中用来标识消息的id,可用于确认消息已接收
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String message = new String(body, "utf-8");
System.out.println("receive message:" + message);
}
};

//监听队列
//参数:String queue, boolean autoAck, Consumer callback
/**
* 参数明细:
* 1、queue 队列名称
* 2、autoAck 自动回复,当消费者接收到消息后要告诉mq消息已接收,如果将此参数设置为tru表示会自动回复mq,如果设置为false要通过编程实现回复
* 3、callback,消费方法,当消费者接收到消息要执行的方法
*/
channel.basicConsume(QUEUE_INFORM_EMAIL, true, defaultConsumer);
}

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
package com.xuecheng.test.rabbitmq;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* @description:
* @author: apple
* @date: 2019-06-01 11:11
*/
public class Consumer02_subscribe_sms {
//队列名称
private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
private static final String EXCHANGE_FANOUT_INFORM = "exchange_fanout_inform";


public static void main(String[] args) throws IOException, TimeoutException {
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");

//建立新连接
Connection connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
Channel channel = connection.createChannel();

/**
* 参数明细
* 1、queue 队列名称
* 2、durable 是否持久化,如果持久化,mq重启后队列还在
* 3、exclusive 是否独占连接,队列只允许在该连接中访问,如果connection连接关闭队列则自动删除,如果将此参数设置true可用于临时队列的创建
* 4、autoDelete 自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
* 5、arguments 参数,可以设置一个队列的扩展参数,比如:可设置存活时间
*/
channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
//声明一个交换机
//参数:String exchange, String type
/**
* 参数明细:
* 1、交换机的名称
* 2、交换机的类型
* fanout:对应的rabbitmq的工作模式是 publish/subscribe
* direct:对应的Routing 工作模式
* topic:对应的Topics工作模式
* headers: 对应的headers工作模式
*/
channel.exchangeDeclare(EXCHANGE_FANOUT_INFORM, BuiltinExchangeType.FANOUT);
//进行交换机和队列绑定
//参数:String queue, String exchange, String routingKey
/**
* 参数明细:
* 1、queue 队列名称
* 2、exchange 交换机名称
* 3、routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
*/
channel.queueBind(QUEUE_INFORM_SMS, EXCHANGE_FANOUT_INFORM, "");
//实现消费方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {

/**
* 当接收到消息后此方法将被调用
* @param consumerTag 消费者标签,用来标识消费者的,在监听队列时设置channel.basicConsume
* @param envelope 信封,通过envelope
* @param properties 消息属性
* @param body 消息内容
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//消息id,mq在channel中用来标识消息的id,可用于确认消息已接收
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String message = new String(body, "utf-8");
System.out.println("receive message:" + message);
}
};

//监听队列
//参数:String queue, boolean autoAck, Consumer callback
/**
* 参数明细:
* 1、queue 队列名称
* 2、autoAck 自动回复,当消费者接收到消息后要告诉mq消息已接收,如果将此参数设置为tru表示会自动回复mq,如果设置为false要通过编程实现回复
* 3、callback,消费方法,当消费者接收到消息要执行的方法
*/
channel.basicConsume(QUEUE_INFORM_SMS, true, defaultConsumer);
}
}

Routing 路由模式

image-20190601112222647

![image-20190601112252365](../../../Users/apple/Library/Application Support/typora-user-images/image-20190601112252365.png)![image-20190601112252639](../../../Users/apple/Library/Application Support/typora-user-images/image-20190601112252639.png)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package com.xuecheng.test.rabbitmq;

import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* @author Administrator
* @version 1.0
* @create 2018-06-17 19:23
**/
public class Producer03_routing {
//队列名称
private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
private static final String EXCHANGE_ROUTING_INFORM="exchange_routing_inform";
private static final String ROUTINGKEY_EMAIL="inform_email";
private static final String ROUTINGKEY_SMS="inform_sms";
public static void main(String[] args) {
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");

Connection connection = null;
Channel channel = null;
try {
//建立新连接
connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
channel = connection.createChannel();
//声明队列,如果队列在mq 中没有则要创建
//参数:String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
/**
* 参数明细
* 1、queue 队列名称
* 2、durable 是否持久化,如果持久化,mq重启后队列还在
* 3、exclusive 是否独占连接,队列只允许在该连接中访问,如果connection连接关闭队列则自动删除,如果将此参数设置true可用于临时队列的创建
* 4、autoDelete 自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
* 5、arguments 参数,可以设置一个队列的扩展参数,比如:可设置存活时间
*/
channel.queueDeclare(QUEUE_INFORM_EMAIL,true,false,false,null);
channel.queueDeclare(QUEUE_INFORM_SMS,true,false,false,null);
//声明一个交换机
//参数:String exchange, String type
/**
* 参数明细:
* 1、交换机的名称
* 2、交换机的类型
* fanout:对应的rabbitmq的工作模式是 publish/subscribe
* direct:对应的Routing 工作模式
* topic:对应的Topics工作模式
* headers: 对应的headers工作模式
*/
channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
//进行交换机和队列绑定
//参数:String queue, String exchange, String routingKey
/**
* 参数明细:
* 1、queue 队列名称
* 2、exchange 交换机名称
* 3、routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
*/
channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_ROUTING_INFORM,ROUTINGKEY_EMAIL);
channel.queueBind(QUEUE_INFORM_EMAIL,EXCHANGE_ROUTING_INFORM,"inform");
channel.queueBind(QUEUE_INFORM_SMS,EXCHANGE_ROUTING_INFORM,ROUTINGKEY_SMS);
channel.queueBind(QUEUE_INFORM_SMS,EXCHANGE_ROUTING_INFORM,"inform");
//发送消息
//参数:String exchange, String routingKey, BasicProperties props, byte[] body
/**
* 参数明细:
* 1、exchange,交换机,如果不指定将使用mq的默认交换机(设置为"")
* 2、routingKey,路由key,交换机根据路由key来将消息转发到指定的队列,如果使用默认交换机,routingKey设置为队列的名称
* 3、props,消息的属性
* 4、body,消息内容
*/
/* for(int i=0;i<5;i++){
//发送消息的时候指定routingKey
String message = "send email inform message to user";
channel.basicPublish(EXCHANGE_ROUTING_INFORM,ROUTINGKEY_EMAIL,null,message.getBytes());
System.out.println("send to mq "+message);
}
for(int i=0;i<5;i++){
//发送消息的时候指定routingKey
String message = "send sms inform message to user";
channel.basicPublish(EXCHANGE_ROUTING_INFORM,ROUTINGKEY_SMS,null,message.getBytes());
System.out.println("send to mq "+message);
}*/
for(int i=0;i<5;i++){
//发送消息的时候指定routingKey
String message = "send inform message to user";
channel.basicPublish(EXCHANGE_ROUTING_INFORM,"inform",null,message.getBytes());
System.out.println("send to mq "+message);
}

} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接
//先关闭通道
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}


}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package com.xuecheng.test.rabbitmq;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* @author Administrator
* @version 1.0
* @create 2018-06-17 18:22
**/
public class Consumer03_routing_email {
//队列名称
private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
private static final String EXCHANGE_ROUTING_INFORM="exchange_routing_inform";
private static final String ROUTINGKEY_EMAIL="inform_email";

public static void main(String[] args) throws IOException, TimeoutException {
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");

//建立新连接
Connection connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
Channel channel = connection.createChannel();

/**
* 参数明细
* 1、queue 队列名称
* 2、durable 是否持久化,如果持久化,mq重启后队列还在
* 3、exclusive 是否独占连接,队列只允许在该连接中访问,如果connection连接关闭队列则自动删除,如果将此参数设置true可用于临时队列的创建
* 4、autoDelete 自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
* 5、arguments 参数,可以设置一个队列的扩展参数,比如:可设置存活时间
*/
channel.queueDeclare(QUEUE_INFORM_EMAIL,true,false,false,null);
//声明一个交换机
//参数:String exchange, String type
/**
* 参数明细:
* 1、交换机的名称
* 2、交换机的类型
* fanout:对应的rabbitmq的工作模式是 publish/subscribe
* direct:对应的Routing 工作模式
* topic:对应的Topics工作模式
* headers: 对应的headers工作模式
*/
channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
//进行交换机和队列绑定
//参数:String queue, String exchange, String routingKey
/**
* 参数明细:
* 1、queue 队列名称
* 2、exchange 交换机名称
* 3、routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
*/
channel.queueBind(QUEUE_INFORM_EMAIL, EXCHANGE_ROUTING_INFORM,ROUTINGKEY_EMAIL);

//实现消费方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel){

/**
* 当接收到消息后此方法将被调用
* @param consumerTag 消费者标签,用来标识消费者的,在监听队列时设置channel.basicConsume
* @param envelope 信封,通过envelope
* @param properties 消息属性
* @param body 消息内容
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//消息id,mq在channel中用来标识消息的id,可用于确认消息已接收
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String message= new String(body,"utf-8");
System.out.println("receive message:"+message);
}
};

//监听队列
//参数:String queue, boolean autoAck, Consumer callback
/**
* 参数明细:
* 1、queue 队列名称
* 2、autoAck 自动回复,当消费者接收到消息后要告诉mq消息已接收,如果将此参数设置为tru表示会自动回复mq,如果设置为false要通过编程实现回复
* 3、callback,消费方法,当消费者接收到消息要执行的方法
*/
channel.basicConsume(QUEUE_INFORM_EMAIL,true,defaultConsumer);

}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package com.xuecheng.test.rabbitmq;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* @author Administrator
* @version 1.0
* @create 2018-06-17 18:22
**/
public class Consumer03_routing_sms {
//队列名称
private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
private static final String EXCHANGE_ROUTING_INFORM="exchange_routing_inform";
private static final String ROUTINGKEY_SMS="inform_sms";

public static void main(String[] args) throws IOException, TimeoutException {
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");

//建立新连接
Connection connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
Channel channel = connection.createChannel();

/**
* 参数明细
* 1、queue 队列名称
* 2、durable 是否持久化,如果持久化,mq重启后队列还在
* 3、exclusive 是否独占连接,队列只允许在该连接中访问,如果connection连接关闭队列则自动删除,如果将此参数设置true可用于临时队列的创建
* 4、autoDelete 自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
* 5、arguments 参数,可以设置一个队列的扩展参数,比如:可设置存活时间
*/
channel.queueDeclare(QUEUE_INFORM_SMS,true,false,false,null);
//声明一个交换机
//参数:String exchange, String type
/**
* 参数明细:
* 1、交换机的名称
* 2、交换机的类型
* fanout:对应的rabbitmq的工作模式是 publish/subscribe
* direct:对应的Routing 工作模式
* topic:对应的Topics工作模式
* headers: 对应的headers工作模式
*/
channel.exchangeDeclare(EXCHANGE_ROUTING_INFORM, BuiltinExchangeType.DIRECT);
//进行交换机和队列绑定
//参数:String queue, String exchange, String routingKey
/**
* 参数明细:
* 1、queue 队列名称
* 2、exchange 交换机名称
* 3、routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
*/
channel.queueBind(QUEUE_INFORM_SMS, EXCHANGE_ROUTING_INFORM,ROUTINGKEY_SMS);

//实现消费方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel){

/**
* 当接收到消息后此方法将被调用
* @param consumerTag 消费者标签,用来标识消费者的,在监听队列时设置channel.basicConsume
* @param envelope 信封,通过envelope
* @param properties 消息属性
* @param body 消息内容
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//消息id,mq在channel中用来标识消息的id,可用于确认消息已接收
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String message= new String(body,"utf-8");
System.out.println("receive message:"+message);
}
};

//监听队列
//参数:String queue, boolean autoAck, Consumer callback
/**
* 参数明细:
* 1、queue 队列名称
* 2、autoAck 自动回复,当消费者接收到消息后要告诉mq消息已接收,如果将此参数设置为tru表示会自动回复mq,如果设置为false要通过编程实现回复
* 3、callback,消费方法,当消费者接收到消息要执行的方法
*/
channel.basicConsume(QUEUE_INFORM_SMS,true,defaultConsumer);

}
}

Toptic 通配符 模式

![image-20190601114259700](../../../Users/apple/Library/Application Support/typora-user-images/image-20190601114259700.png)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
package com.xuecheng.test.rabbitmq;
import com.rabbitmq.client.BuiltinExchangeType;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Producer04_topics {
//队列名称
private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
private static final String EXCHANGE_TOPICS_INFORM = "exchange_topics_inform";
private static final String ROUTINGKEY_EMAIL = "inform.#.email.#";
private static final String ROUTINGKEY_SMS = "inform.#.sms.#";

public static void main(String[] args) {
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");

Connection connection = null;
Channel channel = null;
try {
//建立新连接
connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
channel = connection.createChannel();
//声明队列,如果队列在mq 中没有则要创建
//参数:String queue, boolean durable, boolean exclusive, boolean autoDelete, Map<String, Object> arguments
/**
* 参数明细
* 1、queue 队列名称
* 2、durable 是否持久化,如果持久化,mq重启后队列还在
* 3、exclusive 是否独占连接,队列只允许在该连接中访问,如果connection连接关闭队列则自动删除,如果将此参数设置true可用于临时队列的创建
* 4、autoDelete 自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
* 5、arguments 参数,可以设置一个队列的扩展参数,比如:可设置存活时间
*/
channel.queueDeclare(QUEUE_INFORM_EMAIL, true, false, false, null);
channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
//声明一个交换机
//参数:String exchange, String type
/**
* 参数明细:
* 1、交换机的名称
* 2、交换机的类型
* fanout:对应的rabbitmq的工作模式是 publish/subscribe
* direct:对应的Routing 工作模式
* topic:对应的Topics工作模式
* headers: 对应的headers工作模式
*/
channel.exchangeDeclare(EXCHANGE_TOPICS_INFORM, BuiltinExchangeType.TOPIC);
//进行交换机和队列绑定
//参数:String queue, String exchange, String routingKey
/**
* 参数明细:
* 1、queue 队列名称
* 2、exchange 交换机名称
* 3、routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
*/
channel.queueBind(QUEUE_INFORM_EMAIL, EXCHANGE_TOPICS_INFORM, ROUTINGKEY_EMAIL);
channel.queueBind(QUEUE_INFORM_SMS, EXCHANGE_TOPICS_INFORM, ROUTINGKEY_SMS);
//发送消息
//参数:String exchange, String routingKey, BasicProperties props, byte[] body
/**
* 参数明细:
* 1、exchange,交换机,如果不指定将使用mq的默认交换机(设置为"")
* 2、routingKey,路由key,交换机根据路由key来将消息转发到指定的队列,如果使用默认交换机,routingKey设置为队列的名称
* 3、props,消息的属性
* 4、body,消息内容
*/
for (int i = 0; i < 5; i++) {
//发送消息的时候指定routingKey
String message = "send email inform message to user";
channel.basicPublish(EXCHANGE_TOPICS_INFORM, "inform.email", null, message.getBytes());
System.out.println("send to mq " + message);
}
for (int i = 0; i < 5; i++) {
//发送消息的时候指定routingKey
String message = "send sms inform message to user";
channel.basicPublish(EXCHANGE_TOPICS_INFORM, "inform.sms", null, message.getBytes());
System.out.println("send to mq " + message);
}
for (int i = 0; i < 5; i++) {
//发送消息的时候指定routingKey
String message = "send sms and email inform message to user";
channel.basicPublish(EXCHANGE_TOPICS_INFORM, "inform.sms.email", null, message.getBytes());
System.out.println("send to mq " + message);
}


} catch (Exception e) {
e.printStackTrace();
} finally {
//关闭连接
//先关闭通道
try {
channel.close();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
connection.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
package com.xuecheng.test.rabbitmq;

import com.rabbitmq.client.*;

import java.io.IOException;
import java.util.concurrent.TimeoutException;

/**
* @author Administrator
* @version 1.0
* @create 2018-06-17 18:22
**/
public class Consumer04_topics_email {
//队列名称
private static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
private static final String EXCHANGE_TOPICS_INFORM="exchange_topics_inform";
private static final String ROUTINGKEY_EMAIL="inform.#.email.#";

public static void main(String[] args) throws IOException, TimeoutException {
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");

//建立新连接
Connection connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
Channel channel = connection.createChannel();

/**
* 参数明细
* 1、queue 队列名称
* 2、durable 是否持久化,如果持久化,mq重启后队列还在
* 3、exclusive 是否独占连接,队列只允许在该连接中访问,如果connection连接关闭队列则自动删除,如果将此参数设置true可用于临时队列的创建
* 4、autoDelete 自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
* 5、arguments 参数,可以设置一个队列的扩展参数,比如:可设置存活时间
*/
channel.queueDeclare(QUEUE_INFORM_EMAIL,true,false,false,null);
//声明一个交换机
//参数:String exchange, String type
/**
* 参数明细:
* 1、交换机的名称
* 2、交换机的类型
* fanout:对应的rabbitmq的工作模式是 publish/subscribe
* direct:对应的Routing 工作模式
* topic:对应的Topics工作模式
* headers: 对应的headers工作模式
*/
channel.exchangeDeclare(EXCHANGE_TOPICS_INFORM, BuiltinExchangeType.TOPIC);
//进行交换机和队列绑定
//参数:String queue, String exchange, String routingKey
/**
* 参数明细:
* 1、queue 队列名称
* 2、exchange 交换机名称
* 3、routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
*/
channel.queueBind(QUEUE_INFORM_EMAIL, EXCHANGE_TOPICS_INFORM,ROUTINGKEY_EMAIL);

//实现消费方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel){

/**
* 当接收到消息后此方法将被调用
* @param consumerTag 消费者标签,用来标识消费者的,在监听队列时设置channel.basicConsume
* @param envelope 信封,通过envelope
* @param properties 消息属性
* @param body 消息内容
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//消息id,mq在channel中用来标识消息的id,可用于确认消息已接收
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String message= new String(body,"utf-8");
System.out.println("receive message:"+message);
}
};

//监听队列
//参数:String queue, boolean autoAck, Consumer callback
/**
* 参数明细:
* 1、queue 队列名称
* 2、autoAck 自动回复,当消费者接收到消息后要告诉mq消息已接收,如果将此参数设置为tru表示会自动回复mq,如果设置为false要通过编程实现回复
* 3、callback,消费方法,当消费者接收到消息要执行的方法
*/
channel.basicConsume(QUEUE_INFORM_EMAIL,true,defaultConsumer);

}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
package com.xuecheng.test.rabbitmq;
import com.rabbitmq.client.*;
import java.io.IOException;
import java.util.concurrent.TimeoutException;
public class Consumer04_topics_sms {
//队列名称
private static final String QUEUE_INFORM_SMS = "queue_inform_sms";
private static final String EXCHANGE_TOPICS_INFORM = "exchange_topics_inform";
private static final String ROUTINGKEY_SMS = "inform.#.sms.#";

public static void main(String[] args) throws IOException, TimeoutException {
//通过连接工厂创建新的连接和mq建立连接
ConnectionFactory connectionFactory = new ConnectionFactory();
connectionFactory.setHost("127.0.0.1");
connectionFactory.setPort(5672);//端口
connectionFactory.setUsername("guest");
connectionFactory.setPassword("guest");
//设置虚拟机,一个mq服务可以设置多个虚拟机,每个虚拟机就相当于一个独立的mq
connectionFactory.setVirtualHost("/");
//建立新连接
Connection connection = connectionFactory.newConnection();
//创建会话通道,生产者和mq服务所有通信都在channel通道中完成
Channel channel = connection.createChannel();

/**
* 参数明细
* 1、queue 队列名称
* 2、durable 是否持久化,如果持久化,mq重启后队列还在
* 3、exclusive 是否独占连接,队列只允许在该连接中访问,如果connection连接关闭队列则自动删除,如果将此参数设置true可用于临时队列的创建
* 4、autoDelete 自动删除,队列不再使用时是否自动删除此队列,如果将此参数和exclusive参数设置为true就可以实现临时队列(队列不用了就自动删除)
* 5、arguments 参数,可以设置一个队列的扩展参数,比如:可设置存活时间
*/
channel.queueDeclare(QUEUE_INFORM_SMS, true, false, false, null);
//声明一个交换机
//参数:String exchange, String type
/**
* 参数明细:
* 1、交换机的名称
* 2、交换机的类型
* fanout:对应的rabbitmq的工作模式是 publish/subscribe
* direct:对应的Routing 工作模式
* topic:对应的Topics工作模式
* headers: 对应的headers工作模式
*/
channel.exchangeDeclare(EXCHANGE_TOPICS_INFORM, BuiltinExchangeType.TOPIC);
//进行交换机和队列绑定
//参数:String queue, String exchange, String routingKey
/**
* 参数明细:
* 1、queue 队列名称
* 2、exchange 交换机名称
* 3、routingKey 路由key,作用是交换机根据路由key的值将消息转发到指定的队列中,在发布订阅模式中调协为空字符串
*/
channel.queueBind(QUEUE_INFORM_SMS, EXCHANGE_TOPICS_INFORM, ROUTINGKEY_SMS);

//实现消费方法
DefaultConsumer defaultConsumer = new DefaultConsumer(channel) {

/**
* 当接收到消息后此方法将被调用
* @param consumerTag 消费者标签,用来标识消费者的,在监听队列时设置channel.basicConsume
* @param envelope 信封,通过envelope
* @param properties 消息属性
* @param body 消息内容
* @throws IOException
*/
@Override
public void handleDelivery(String consumerTag, Envelope envelope, AMQP.BasicProperties properties, byte[] body) throws IOException {
//交换机
String exchange = envelope.getExchange();
//消息id,mq在channel中用来标识消息的id,可用于确认消息已接收
long deliveryTag = envelope.getDeliveryTag();
//消息内容
String message = new String(body, "utf-8");
System.out.println("receive message:" + message);
}
};
//监听队列
//参数:String queue, boolean autoAck, Consumer callback
/**
* 参数明细:
* 1、queue 队列名称
* 2、autoAck 自动回复,当消费者接收到消息后要告诉mq消息已接收,如果将此参数设置为tru表示会自动回复mq,如果设置为false要通过编程实现回复
* 3、callback,消费方法,当消费者接收到消息要执行的方法
*/
channel.basicConsume(QUEUE_INFORM_SMS, true, defaultConsumer);
}
}

image-20190601154847105


SpringBoot 整合RabbitMQ

1
2
3
4
5
6
7
8
9
10
11
12
13
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-amqp</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</dependency>
</dependencies>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
package com.xuecheng.test.rabbitmq;

import com.xuecheng.test.rabbitmq.config.RabbitmqConfig;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

/**
* @author Administrator
* @version 1.0
* @create 2018-06-17 19:23
**/
@SpringBootTest
@RunWith(SpringRunner.class)
public class Producer05_topic_springboot {
@Autowired
RabbitTemplate rabbitTemplate;

//使用rabbitTemplate发送消息
@Test
public void testSendEmail() {
String message = "send email message to user";
/**
* 参数:
* 1、交换机名称
* 2、routingKey
* 3、消息内容
*/
rabbitTemplate.convertAndSend(RabbitmqConfig.EXCHANGE_TOPICS_INFORM, "inform.email", message);

}
//使用rabbitTemplate发送消息
// @Test
// public void testSendPostPage() {
//
// Map message = new HashMap<>();
// message.put("pageId", "5a795ac7dd573c04508f3a56");
// //将消息对象转成json串
// String messageString = JSON.toJSONString(message);
// //路由key,就是站点ID
// String routingKey = "5a751fab6abb5044e0d19ea1";
// /**
// * 参数:
// * 1、交换机名称
// * 2、routingKey
// * 3、消息内容
// */
// rabbitTemplate.convertAndSend("ex_routing_cms_postpage", routingKey, messageString);
//
// }

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
package com.xuecheng.test.rabbitmq.config;

import org.springframework.amqp.core.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @author Administrator
* @version 1.0
* @create 2018-06-17 20:45
**/
@Configuration
public class RabbitmqConfig {
public static final String QUEUE_INFORM_EMAIL = "queue_inform_email";
public static final String QUEUE_INFORM_SMS = "queue_inform_sms";
public static final String EXCHANGE_TOPICS_INFORM = "exchange_topics_inform";
public static final String ROUTINGKEY_EMAIL = "inform.#.email.#";
public static final String ROUTINGKEY_SMS = "inform.#.sms.#";

//声明交换机
@Bean(EXCHANGE_TOPICS_INFORM)
public Exchange EXCHANGE_TOPICS_INFORM() {
//durable(true) 持久化,mq重启之后交换机还在
//Bug:durable设置成(true)
/*
Caused by:com.rabbitmq.client.ShutdownSignalException:channel error;
protocol method: #method<channel.close> (reply - code = 406, reply - text = PRECONDITION_FAILED - inequivalent
arg 'durable' for exchange 'exchange_topics_inform' in vhost '/':received 'true' but current is 'false',class
-id = 40, method - id = 10)
*/
return ExchangeBuilder.topicExchange(EXCHANGE_TOPICS_INFORM).durable(false).build();
}

//声明QUEUE_INFORM_EMAIL队列
@Bean(QUEUE_INFORM_EMAIL)
public Queue QUEUE_INFORM_EMAIL() {
return new Queue(QUEUE_INFORM_EMAIL);
}

//声明QUEUE_INFORM_SMS队列
@Bean(QUEUE_INFORM_SMS)
public Queue QUEUE_INFORM_SMS() {
return new Queue(QUEUE_INFORM_SMS);
}

//ROUTINGKEY_EMAIL队列绑定交换机,指定routingKey
@Bean
public Binding BINDING_QUEUE_INFORM_EMAIL(@Qualifier(QUEUE_INFORM_EMAIL) Queue queue,
@Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_EMAIL).noargs();
}

//ROUTINGKEY_SMS队列绑定交换机,指定routingKey
@Bean
public Binding BINDING_ROUTINGKEY_SMS(@Qualifier(QUEUE_INFORM_SMS) Queue queue,
@Qualifier(EXCHANGE_TOPICS_INFORM) Exchange exchange) {
return BindingBuilder.bind(queue).to(exchange).with(ROUTINGKEY_SMS).noargs();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package com.xuecheng.test.rabbitmq;

import com.xuecheng.test.rabbitmq.config.RabbitmqConfig;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.stereotype.Component;

import java.nio.channels.Channel;

@Component
public class ReceiveHandler {
@RabbitListener(queues = {RabbitmqConfig.QUEUE_INFORM_EMAIL})
public void send_email(String msg, Message message, Channel channel) {
System.out.println("接受到的数据是" + msg);
}

}
1
2
3
4
5
6
7
8
9
10
11
server:
port: 44000
spring:
application:
name: test-rabbitmq-producer
rabbitmq:
host: 127.0.0.1
port: 5672
username: guest
password: guest
virtualHost: /

第七章 页面管理

![image-20190601185717863](../../../Users/apple/Library/Application Support/typora-user-images/image-20190601185717863.png)

![image-20190601185741185](../../../Users/apple/Library/Application Support/typora-user-images/image-20190601185741185.png)![image-20190601185741530](../../../Users/apple/Library/Application Support/typora-user-images/image-20190601185741530.png)

![image-20190601185832865](../../../Users/apple/Library/Application Support/typora-user-images/image-20190601185832865.png)


课程管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
server:
port: 31200
spring:
application:
name: xc-service-manage-course
datasource:
druid:
url: jdbc:mysql://localhost:3306/xc_course?characterEncoding=utf-8
username: root
password: YHP836143
#driverClassName: com.mysql.jdbc.Driver
driverClassName: com.mysql.cj.jdbc.Driver
initialSize: 5 #初始建立连接数量
minIdle: 5 #最小连接数量
maxActive: 20 #最大连接数量
maxWait: 10000 #获取连接最大等待时间,毫秒
testOnBorrow: true #申请连接时检测连接是否有效
testOnReturn: false #归还连接时检测连接是否有效
timeBetweenEvictionRunsMillis: 60000 #配置间隔检测连接是否有效的时间(单位是毫秒)
minEvictableIdleTimeMillis: 300000 #连接在连接池的最小生存时间(毫秒)

1
2
3
4
5
6
<mapper namespace="com.xuecheng.manage_course.dao.CourseMapper">
<select id="findCourseBaseById" parameterType="java.lang.String"
resultType="com.xuecheng.framework.domain.course.CourseBase">
select * from course_base where id = #{id}
</select>
</mapper>
1
2
3
4
@Mapper
public interface CourseMapper {
CourseBase findCourseBaseById(String id);
}
1
2
3
4
5
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.14</version>
</dependency>
1
2
public interface CourseBaseRepository extends JpaRepository<CourseBase,String> {
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@SpringBootTest
@RunWith(SpringRunner.class)

public class TestDao {
@Autowired
CourseBaseRepository courseBaseRepository;
@Autowired
CourseMapper courseMapper;

@Test
public void testCourseBaseRepository() {
Optional<CourseBase> optional = courseBaseRepository.findById("402885816240d276016240f7e5000002");
if (optional.isPresent()) {
CourseBase courseBase = optional.get();
System.out.println(courseBase);
}

}

@Test
public void testCourseMapper() {
CourseBase courseBase = courseMapper.findCourseBaseById("402885816240d276016240f7e5000002");
System.out.println(courseBase);

}
}

导入前端Vue工程 报错

image-20190610112859272


mybatis不要写注释

课程计划查询接口(SQL)

image-20190610152215668

关于left on

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >
<mapper namespace="com.xuecheng.manage_course.dao.TeachplanMapper">
<resultMap id="teachplanMap" type="com.xuecheng.framework.domain.course.ext.TeachplanNode">
<id column="one_id" property="id"></id>
<result column="one_pname" property="pname"></result>
//一对多
<collection property="children" ofType="com.xuecheng.framework.domain.course.ext.TeachplanNode">
<id column="two_id" property="id"></id>
<result column="two_pname" property="pname"></result>
<collection property="children" ofType="com.xuecheng.framework.domain.course.ext.TeachplanNode">
<id column="three_id" property="id"></id>
<result column="three_pname" property="pname"></result>
</collection>
</collection>
</resultMap>

<select id="selectList" parameterType="java.lang.String"
resultMap="teachplanMap">
SELECT
a.id one_id,
a.pname one_pname,
b.id two_id,
b.pname two_pname,
c.id three_id,
c.pname three_pname
FROM
teachplan a
LEFT JOIN teachplan b
ON b.parentid = a.id
LEFT JOIN teachplan c
ON c.parentid = b.id
WHERE a.parentid = '0'
<if test="_parameter !=null and _parameter!=''">
AND a.courseid = #{courseId}
</if>
ORDER BY a.orderby,
b.orderby,
c.orderby
</select>
</mapper>

》前端工程 没有用 更换node.js的版本

image-20190610175444320

FastDFS 文件上传

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
server:
port: 22100
spring:
application:
name: xc-service-base-filesystem
#mongo配置
data:
mongodb:
host: localhost
port: 27017
database: xc_fs
# data:
# mongodb:
# database: xc_fs
# uri: mongodb://root:123@127.0.0.1:27017
#SpringMVC上传文件配置
servlet:
multipart:
#默认支持文件上传.
enabled: true
#支持文件写入磁盘.
file-size-threshold: 0
# 上传文件的临时目录
location:
# 最大支持文件大小
max-file-size: 1MB
# 最大支持请求大小
max-request-size: 30MB
xuecheng:
fastdfs:
connect_timeout_in_seconds: 5
network_timeout_in_seconds: 30
charset: UTF-8
tracker_servers: 192.168.0.106:22122 #多个 trackerServer中间以逗号分隔
1
2
3
4
5
6
7
8
9
10
11
12
@RestController
@RequestMapping("/filesystem")
public class FileSystemController implements FileSystemControllerApi {
@Autowired
FileSystemService fileSystemService;

@Override
@GetMapping("/upload")
public UploadFileResult upload(MultipartFile multipartFile, String filetag, String businesskey, String metadata) throws IOException {
return fileSystemService.upload(multipartFile, filetag, businesskey, metadata);
}
}

第八章 Eureka Feign

1
2
3
4
5
<!-- 导入Eureka服务的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
1
2
3
4
5
6
7
@EnableEurekaServer //标识此工程是一个EurekaServer
@SpringBootApplication
public class GovernCenterApplication {
public static void main(String[] args) {
SpringApplication.run(GovernCenterApplication.class,args);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
server:
port: ${PORT:50101} #服务端口
spring:
application:
name: xc-govern-center #指定服务名
eureka:
client:
registerWithEureka: true #服务注册,是否将自己注册到Eureka服务中
fetchRegistry: true #服务发现,是否从Eureka中获取注册信息
serviceUrl: #Eureka客户端与Eureka服务端的交互地址,高可用状态配置对方的地址,单机状态配置自己(如果不配置则默认本机8761端口)
defaultZone: ${EUREKA_SERVER:http://eureka02:50102/eureka/}
server:
enable-self-preservation: false #是否开启自我保护模式
eviction-interval-timer-in-ms: 60000 #服务注册表清理间隔(单位毫秒,默认是60*1000)
instance:
hostname: ${EUREKA_DOMAIN:eureka01}
1
2
3
4
5
<!-- 导入Eureka客户端的依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
eureka:
client:
registerWithEureka: true #服务注册开关
fetchRegistry: true #服务发现开关
serviceUrl: #Eureka客户端与Eureka服务端进行交互的地址,多个中间用逗号分隔
defaultZone: ${EUREKA_SERVER:http://localhost:50101/eureka/,http://localhost:50102/eureka/}
instance:
prefer-ip-address: true #将自己的ip地址注册到Eureka服务中
ip-address: ${IP_ADDRESS:127.0.0.1}
instance-id: ${spring.application.name}:${server.port} #指定实例id
ribbon:
MaxAutoRetries: 2 #最大重试次数,当Eureka中可以找到服务,但是服务连不上时将会重试
MaxAutoRetriesNextServer: 3 #切换实例的重试次数
OkToRetryOnAllOperations: false #对所有操作请求都进行重试,如果是get则可以,如果是post,put等操作没有实现幂等的情况下是很危险的,所以设置为false
ConnectTimeout: 5000 #请求连接的超时时间
ReadTimeout: 6000 #请求处理的超时时间
course-publish:
siteId: 5b30cba5f58b4411fc6cb1e5
templateId: 5b345a6b94db44269cb2bfec
previewUrl: http://www.xuecheng.com/cms/preview/
pageWebPath: /course/detail/
pagePhysicalPath: /course/detail/
dataUrlPre: http://localhost:31200/course/courseview/
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@SpringBootTest
@RunWith(SpringRunner.class)
public class TestRibbon {
@Autowired
RestTemplate restTemplate;

@Test
public void testRibbon(){
//确定要获取的服务名
String serviceId = "XC-SERVICE-MANAGE-CMS";
for (int i=0;i<10;i++){
//ribbon客户端从eurekaServer中获取服务列表,根据服务名获取服务列表
ResponseEntity<Map> forEntity = restTemplate.getForEntity("http://"+serviceId+"/cms/page/get/5a754adf6abb500ad05688d9", Map.class);
Map body = forEntity.getBody();
System.out.println(body);
}

}

1
@EnableFeignClients//开启Fegin
1
2
3
4
5
6
7
@FeignClient(value = "XC-SERVICE-MANAGE-CMS")
public interface CmsPageClient {
//根据页面id查询页面信息 远程调用cms请求数据
@GetMapping("/cms/page/get/{id}")//表示远程调用的http的方法类型
public CmsPage findCmsPageById(@PathVariable("id") String id);

}
1
2
3
4
5
6
7
8
9
10
11
12
13
public class TestFeign {

@Autowired
CmsPageClient cmsPageClient;

@Test
public void testfing() {
//发起远程调用
CmsPage cmsPageById = cmsPageClient.findCmsPageById("5a754adf6abb500ad05688d9");
System.out.println(cmsPageById);
}

}

第十一章 ElasticSearch

1 DSL搜索

ElasticSearc—Config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
package com.xuecheng.search.config;
import org.apache.http.HttpHost;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
* @description:
* @author: apple
* @date: 2019-06-27 09:35
*/
@Configuration
public class ElasticSearchConfig {

@Value("${xuecheng.elasticsearch.hostlist}")
private String hostlist;

@Bean
public RestHighLevelClient restHighLevelClient() {
//解析hostlist配置信息
String[] split = hostlist.split(",");
//创建HttpHost数组,其中存放es主机和端口的配置信息
HttpHost[] httpHostArray = new HttpHost[split.length];
for (int i = 0; i < split.length; i++) {
String item = split[i];
httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
}
//创建RestHighLevelClient客户端
return new RestHighLevelClient(RestClient.builder(httpHostArray));
}

//项目主要使用RestHighLevelClient,对于低级的客户端暂时不用
@Bean
public RestClient restClient() {
//解析hostlist配置信息
String[] split = hostlist.split(",");
//创建HttpHost数组,其中存放es主机和端口的配置信息
HttpHost[] httpHostArray = new HttpHost[split.length];
for (int i = 0; i < split.length; i++) {
String item = split[i];
httpHostArray[i] = new HttpHost(item.split(":")[0], Integer.parseInt(item.split(":")[1]), "http");
}
return RestClient.builder(httpHostArray).build();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
server:
port: ${port:40100}
spring:
application:
name: xc-search-service
xuecheng:
elasticsearch:
hostlist: ${eshostlist:127.0.0.1:9200} #多个结点中间用逗号分隔
course:
index: xc_course
type: doc
source_field: id,name,grade,mt,st,charge,valid,pic,qq,price,price_old,status,studymodel,teachmode,expires,pub_time,start_time,end_time

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
package com.xuecheng.search;

import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.client.RestClient;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.index.query.QueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.SearchHits;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import java.io.IOException;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Map;

/**
* @description:
* @author: apple
* @date: 2019-06-27 09:59
*/
@SpringBootTest
@RunWith(SpringRunner.class)
public class testSearch {
@Autowired
RestHighLevelClient client;
@Autowired
RestClient restClient;

//搜索全部记录
@Test
public void testSearchAll() throws IOException, ParseException {
//搜索请求对象
SearchRequest searchRequest = new SearchRequest("xc_course");
//指定类型
searchRequest.types("doc");
//搜索源构建对象
SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder();
//搜索方式
//matchAllQuery搜索全部
searchSourceBuilder.query(QueryBuilders.matchAllQuery());
//设置源字段过虑,第一个参数结果集包括哪些字段,第二个参数表示结果集不包括哪些字段
searchSourceBuilder.fetchSource(new String[]{"name","studymodel","price","timestamp"},new String[]{});
//向搜索请求对象中设置搜索源
searchRequest.source(searchSourceBuilder);
//执行搜索,向ES发起http请求
SearchResponse searchResponse = client.search(searchRequest);
//搜索结果
SearchHits hits = searchResponse.getHits();
//匹配到的总记录数
long totalHits = hits.getTotalHits();
//得到匹配度高的文档
SearchHit[] searchHits = hits.getHits();
//日期格式化对象
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
for(SearchHit hit:searchHits){
//文档的主键
String id = hit.getId();
//源文档内容
Map<String, Object> sourceAsMap = hit.getSourceAsMap();
String name = (String) sourceAsMap.get("name");
//由于前边设置了源文档字段过虑,这时description是取不到的
String description = (String) sourceAsMap.get("description");
//学习模式
String studymodel = (String) sourceAsMap.get("studymodel");
//价格
Double price = (Double) sourceAsMap.get("price");
//日期
Date timestamp = dateFormat.parse((String) sourceAsMap.get("timestamp"));
System.out.println(name);
System.out.println(studymodel);
System.out.println(description);
}

}

}

分页查询

第十五章 SpringSecurity Oauth2